package cn.w.outdoor.lib.media;

import android.media.MediaCodec;
import android.media.MediaCodecInfo;
import android.media.MediaFormat;
import android.util.Log;
import android.view.SurfaceView;

import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.Queue;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.TimeUnit;

import cn.w.outdoor.lib.common.CommonVideoCodecMethods;
import cn.w.outdoor.lib.model.Trans_Package;

public class VideoDecoderAndDisplayThread extends Thread implements OnDataListener {

    private final static String TAG = "VideoDecoderAndDisplay";

    private SurfaceView surfaceView;

    public VideoDecoderAndDisplayThread(SurfaceView surfaceView) {
        this.surfaceView = surfaceView;
    }

    private boolean stopThread;

    private Queue<Trans_Package> originalVideoBuffer; // 摄像头原始数据队列

    public void stopEncoder() {
        this.stopThread = true;
    }

    @Override
    public void onData(Trans_Package trans_package) {
        if (originalVideoBuffer == null) originalVideoBuffer = new ConcurrentLinkedQueue<>();
//        Log.e(TAG, "onData: 收到其他部分发送过来的 H264 码流数据 长度：" + trans_package.getLen());
        originalVideoBuffer.offer(trans_package);
    }

    @Override
    public void run() {

        try {

            MediaCodecInfo mediaCodecInfo = CommonVideoCodecMethods.selectCodec(MediaConfig.VIDEO_MIME_TYPE);
            if (mediaCodecInfo == null) {
                Log.e(TAG, "执行 selectCodec 失败，启动解码显示线程失败");
                return;
            }

            int colorFormat = CommonVideoCodecMethods.selectColorFormat(mediaCodecInfo, MediaConfig.VIDEO_MIME_TYPE);
            if (colorFormat == -1) {
                Log.e(TAG, "执行 selectColorFormat 失败，启动解码显示线程失败");
                return;
            }


            MediaCodec mediaCodec = MediaCodec.createDecoderByType(MediaConfig.VIDEO_MIME_TYPE);

            MediaFormat format = MediaFormat.createVideoFormat(MediaConfig.VIDEO_MIME_TYPE, MediaConfig.VIDEOWIDTH, MediaConfig.VIDEOHEIGHT);

            format.setInteger(MediaFormat.KEY_COLOR_FORMAT, colorFormat);

            MediaCodec.BufferInfo info = new MediaCodec.BufferInfo();

            stopThread = false;

            mediaCodec.configure(format, surfaceView.getHolder().getSurface(), null, 0);
            mediaCodec.start();

            while (!stopThread) {
                if (originalVideoBuffer == null) {
                    try {
                        TimeUnit.MILLISECONDS.sleep(10);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    continue;
                }
                Trans_Package trans_package = originalVideoBuffer.poll();
                if (trans_package != null && trans_package.getLen() > 0) {
                    ByteBuffer[] decoderInputBuffers = mediaCodec.getInputBuffers();
                    int inputBufferIndex = mediaCodec.dequeueInputBuffer(-1);
                    if (inputBufferIndex >= 0) {
                        ByteBuffer inputBuffer = decoderInputBuffers[inputBufferIndex];
                        inputBuffer.clear();
                        inputBuffer.put(trans_package.generateToBytes(), 16, trans_package.getLen());
                        mediaCodec.queueInputBuffer(inputBufferIndex, 0, trans_package.getLen(),
                                info.presentationTimeUs, info.flags);
                    }
                    int outputBufferIndex = mediaCodec.dequeueOutputBuffer(info, 0);
                    if (outputBufferIndex >= 0) {
                        mediaCodec.releaseOutputBuffer(outputBufferIndex, true);
                    }
                } else {
                    try {
                        TimeUnit.MILLISECONDS.sleep(10);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }

            try {
                mediaCodec.stop();
                mediaCodec.release();
                mediaCodec = null;
            } catch (Exception e) {
                e.printStackTrace();
            }

            originalVideoBuffer.clear();
            originalVideoBuffer = null;
            System.gc();

        } catch (IOException e) {
            e.printStackTrace();
        }

    }

}
